-- GridConfigurableLayouts.lua
--
-- Created By : msaint
-- Credits: Greltok, for his very helpful feedback on my code (and a tiny bit of borrowed code)


--{{{ Hack the localization function for easy implementation later
local L = {}
setmetatable(L,{ __index = function(l, text) return text end})
---}}}
     
     
--{{{ File scope variables
local combatLockdown = false
local isRegistered = false
local rosterZoneList = {}
local currentLayout = nil
local emptyLayout = {
   defaults = {
  	   unitsPerColumn = 5,
	   maxColumns = 8,
	},
	[1] = {
		nameList = "",
	},
}
local outerFrames = {}
local outerPetFrames = {}
---}}}


--{{{ Libraries
local talentLib = LibStub:GetLibrary("LibGroupTalents-1.0")
local GridRoster = Grid:GetModule("GridRoster")
local GridLayout = Grid:GetModule("GridLayout")
local GCLHooks = AceLibrary("AceAddon-2.0"):new("AceHook-2.1")
local Waterfall = AceLibrary("Waterfall-1.0")
local media = LibStub("LibSharedMedia-3.0", true)
--}}}


--{{{ Create the module
GridConfigurableLayouts = Grid:NewModule("GridConfigurableLayouts")
---}}}


---{{{ Module-wide tables and variables
GridConfigurableLayouts.newLayoutName = ""
GridConfigurableLayouts.groupTypes = {
   ["tank"] = L["Tanks"],
   ["blizztank"] = L["Blizzard Tanks"],
   ["melee"] = L["Melee"],
   ["healer"] = L["Healers"],
   ["ranged"] = L["Ranged"],
   ["ooz"] = L["Out Of Zone"],
   ["rg1"] = L["Raid Group 1"],
   ["rg2"] = L["Raid Group 2"],
   ["rg3"] = L["Raid Group 3"],
   ["rg4"] = L["Raid Group 4"],
   ["rg5"] = L["Raid Group 5"],
   ["rg6"] = L["Raid Group 6"],
   ["rg7"] = L["Raid Group 7"],
   ["rg8"] = L["Raid Group 8"],
   ["pets"] = L["Pets"],
   ["empty"] = L["Empty"],
   ["none"] = L["None"],
   ["guild"] = L["Guild"],   
}
---}}}


---{{{ Local functions
local function hasVisibleUnitFrame(f)
   -- This function borrowed from GridLayout.lua with a small modification
	if f:IsVisible() and f:GetAttribute("unit") then
		return true
	end
   for i, f in ipairs({f:GetChildren()}) do
		if hasVisibleUnitFrame(f) then
			return true
		end
	end
end
---}}}


--{{{ AceDB defaults
GridConfigurableLayouts.defaultDB = {
   checkOOZFrequency = 3,
   configLayout = "GCL Default",
   filterToColor = "tank",
   filterColors = {
      ["tank"] = {["r"] = 0.9, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.8},
      ["blizztank"] = {["r"] = 0.9, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.8},
      ["melee"] = {["r"] = 0.9, ["g"] = 0.9, ["b"] = 0.5, ["a"] = 0.8},
      ["healer"] = {["r"] = 0.5, ["g"] = 0.9, ["b"] = 0.5, ["a"] = 0.8},
      ["ranged"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.9, ["a"] = 0.8},
      ["ooz"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg1"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg2"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg3"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg4"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg5"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg6"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg7"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["rg8"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["pets"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["empty"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["none"] = {["r"] = 0.5, ["g"] = 0.5, ["b"] = 0.5, ["a"] = 0.5},
      ["guild"] = {["r"] = 0.3, ["g"] = 0.9, ["b"] = 0.6, ["a"] = 0.5},
   },
   layoutNames = {"GCL Default", "By Group 10 w/ Tanks, Pets", "By Group 25 w/ Tanks, Pets"},
   layouts = {
      ["GCL Default"] = {
         createBorders = true,
         allowRepeats = false,
         numGroups = 6,
         groupType = {"tank", "melee", "healer", "ranged", "pets", "ooz", "none", "none", "none", "none", "none" },
         nameList = {"", "", "", "", "", "", "", "", "", "", "" },
         petOptions = {
            ["allPets"] = false,
            ["HUNTER"] = true,
            ["WARLOCK"] = true,
            ["DEATHKNIGHT"] = true,
         },
      },
      ["By Group 10 w/ Tanks, Pets"] = {
         createBorders = false,
         allowRepeats = false,
         numGroups = 5,
         groupType = {"tank", "rg1", "rg2", "pets", "ooz", "none", "none", "none", "none", "none", "none" },
         nameList = {"", "", "", "", "", "", "", "", "", "", "" },
         petOptions = {
            ["allPets"] = true,
            ["HUNTER"] = true,
            ["WARLOCK"] = true,
            ["DEATHKNIGHT"] = true,
         },
      },
      ["By Group 25 w/ Tanks, Pets"] = {
         createBorders = false,
         allowRepeats = false,
         numGroups = 8,
         groupType = {"tank", "rg1", "rg2", "rg3", "rg4", "rg5", "pets", "ooz", "none", "none", "none" },
         nameList = {"", "", "", "", "", "", "", "", "", "", "" },
         petOptions = {
            ["allPets"] = true,
            ["HUNTER"] = true,
            ["WARLOCK"] = true,
            ["DEATHKNIGHT"] = true,
         },
      }, 
   },
}
--}}}


--{{{ Options Structure
local GCLOptions = {
   ["layoutSelectionHeader"] = { 
	   type = "header",
	   name = L["Layout Selection"],
	   order = 1,
	},
   ["configLayout"] = {
      type = "text",
  	   name = L["Layout to configure:"],
  	   desc = L["Sets which layout configuration changes apply to."],
  	   order = 2,
  	   disabled = InCombatLockdown,
  	   get = function () return GridConfigurableLayouts.db.profile.configLayout end,
  	   set = function (v) GridConfigurableLayouts:loadNewConfig(v) end,
  	   validate = {},
   },
   ["spacer1"] = {
		type = "header",
		name = L[" "],
		order = 5,
	},
	["spacer2"] = {
		type = "header",
		name = L[" "],
		order = 6,
	},
	["spacer3"] = {
		type = "header",
		name = L[" "],
		order = 7,
	},
	["createRemoveHeader"] = { 
	   type = "header",
	   name = L["Create or Remove Layouts"],
	   height = 100,
	   order = 8,
	},
   ["newLayoutName"] = {
      type = "text",
      name = L["Name of layout to create or remove:"],
      desc = L["Name of layout to create or remove (hint: type name then press <enter>)."],
      usage = "What does this do?",
      order = 9,
      disabled = InCombatLockdown,
      get = function () return GridConfigurableLayouts.newLayoutName end,
      set = function (v) 
         GridConfigurableLayouts.newLayoutName = v
         Waterfall:Refresh("Grid")
      end, 
   },
   ["createNewLayout"] = {
      type = "execute",
      name = L["Create New Layout"],
      desc = L["Create a new layout."],
      order = 10,
      disabled = function () return InCombatLockdown() or (not GridConfigurableLayouts.newLayoutName or GridConfigurableLayouts.newLayoutName == "" or GridLayout.layoutSettings[GridConfigurableLayouts.newLayoutName]) end,
      func = function () GridConfigurableLayouts:createLayout(GridConfigurableLayouts.newLayoutName) end,
   },
   ["removeLayout"] = {
      type = "execute",
      name = L["Remove Layout"],
      desc = L["Remove a layout."],
      order = 11,
      disabled = function () return InCombatLockdown() or (not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.newLayoutName] or GridConfigurableLayouts.newLayoutName == "GCL Default") end,
      func = function ()
         GridConfigurableLayouts:removeLayout(GridConfigurableLayouts.newLayoutName)
      end,
   },
	["spacer4"] = {
		type = "header",
		name = L[" "],
		order = 15,
	},
   ["spacer5"] = {
		type = "header",
		name = L[" "],
		order = 16,
	},
   ["spacer6"] = {
		type = "header",
		name = L[" "],
		order = 17,
	},
   ["warningHit Enter"] = { 
	   type = "header",
	   name = L["Note: You must press enter after typing in a text box."],
	   order = 18,
	},
   ["spacer7"] = {
		type = "header",
		name = L[" "],
		order = 19,
	},	
   ["layoutOptions"] = {
      type = "group",
      name = L["Layout Options"],
      desc = L["Options that apply to this layout."],
      order = 25,
      disabled = InCombatLockdown,
      args = {
         ["petOptionsHeader"] = { 
            type = "header",
            name = L["Pet Group Options"],
            order = 3,
	      },
         ["enableAllPets"] = {
            type = "toggle",
            name = L["Display all raid pets"],
            desc = L["Display raid pets for all pet classes."],
            order = 4,
            disabled = InCombatLockdown,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"] end,
            set = function ()
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"] =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"]
               GridConfigurableLayouts:checkUpdateCurrent()
               Waterfall:Refresh("Grid")
            end, 
         },
         ["enableHunterPets"] = {
            type = "toggle",
            name = L["Display hunter pets"],
            desc = L["Display raid pets for hunters."],
            disabled = function () return InCombatLockdown() or GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"] end, 
            order = 5,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["HUNTER"] end,
            set = function ()
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["HUNTER"] =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["HUNTER"]
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
         ["enableWarlockPets"] = {
            type = "toggle",
            name = L["Display warlock pets"],
            desc = L["Display raid pets for warlocks."],
            disabled = function () return InCombatLockdown() or GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"] end,
            order = 6,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["WARLOCK"] end,
            set = function ()
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["WARLOCK"] =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["WARLOCK"]
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
         ["enableDeathknighPets"] = {
            type = "toggle",
            name = L["Display deathknight pets"],
            desc = L["Display raid pets for deathknights."],
            disabled = function () return InCombatLockdown() or GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["allPets"] end,
            order = 7,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["DEATHKNIGHT"] end,
            set = function ()
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["DEATHKNIGHT"] =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].petOptions["DEATHKNIGHT"]
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
         ["spacer1"] = {
      		type = "header",
      		name = L[" "],
      		order = 10,
	      },
         ["spacer2"] = {
		      type = "header",
		      name = L[" "],
            order = 11,
         },
         --["spacer3"] = {
         --   type = "header",
         --   name = L[" "],
         --   order = 12,
	      --},
         ["otherOptionsHeader"] = { 
            type = "header",
            name = L["Other Layout Options"],
            order = 15,
	      },
         ["allowRepeats"] = {
        	   type = "toggle",
           	name = L["Allow repeats"],
           	desc = L["Show raid members in all groups that apply, instead of only once"],
           	order = 16,
           	disabled = InCombatLockdown,
           	get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].allowRepeats end,
           	set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].allowRepeats =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].allowRepeats
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
         ["offlineIsOOZ"] = {
        	   type = "toggle",
           	name = L["Treat offline as out of zone"],
           	desc = L["Put raid members that are offline in out of zone group, if present."],
           	order = 17,
           	disabled = InCombatLockdown,
           	get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].offlineIsOOZ end,
           	set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].offlineIsOOZ =
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].offlineIsOOZ
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
      	["createBorders"] = {
            type = "toggle",
            name = L["Replace Grid Border with Group Borders"],
            desc = L["Enable creation of colored borders around groups. Uses GridLayout border texture.\nHint: play with your padding under Layout."],
            order = 18,
            disabled = InCombatLockdown,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].createBorders end,
            set = function ()
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].createBorders = 
                  not GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].createBorders
               GridConfigurableLayouts:checkUpdateCurrent()
            end, 
         },
      },
   },
   ["editGroupFilters"] = {
      type = "group",
      name = L["Group Filters"],
      desc = L["Select filters to apply to groups in the current layout."],
      order = 27,
      disabled = InCombatLockdown,
      args = {
         ["groupType1"] = {
            type = "text",
            name = L["Group 1:"],
        	   desc = L["Sets contents of the first grid group."],
            order = 2,
            disabled = InCombatLockdown,
            hidden = false,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[1] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[1] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
        	   validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType2"] = {
            type = "text",
        	   name = L["Group 2:"],
        	   desc = L["Sets contents of the second grid group."],
        	   order = 3,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[2] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[2] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
        	   validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType3"] = {
            type = "text",
        	   name = L["Group 3:"],
        	   desc = L["Sets contents of the third grid group."],
        	   order = 5,
        	   disabled = InCombatLockdown,
        	   hidden = true,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[3] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[3] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType4"] = {
            type = "text",
        	   name = L["Group 4:"],
        	   desc = L["Sets contents of the fourth grid group."],
        	   order = 6,
        	   disabled = InCombatLockdown,
        	   hidden = true,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[4] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[4] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType5"] = {
            type = "text",
        	   name = L["Group 5:"],
        	   desc = L["Sets contents of the fifth grid group."],
        	   order = 7,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[5] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[5] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType6"] = {
            type = "text",
        	   name = L["Group 6:"],
        	   desc = L["Sets contents of the sixth grid group."],
        	   order = 8,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[6] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[6] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType7"] = {
            type = "text",
        	   name = L["Group 7:"],
        	   desc = L["Sets contents of the seventh grid group."],
        	   order = 9,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[7] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[7] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType8"] = {
            type = "text",
        	   name = L["Group 8:"],
           	desc = L["Sets contents of the eighth grid group."],
        	   order = 10,
        	   disabled = InCombatLockdown,
        	   hidden = true,
           	get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[8] end,
           	set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[8] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType9"] = {
            type = "text",
        	   name = L["Group 9:"],
        	   desc = L["Sets contents of the ninth grid group."],
        	   order = 11,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[9] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[9] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
        	   validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType10"] = {
            type = "text",
        	   name = L["Group 10:"],
        	   desc = L["Sets contents of the tenth grid group."],
        	   order = 12,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[10] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[10] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
           	validate = GridConfigurableLayouts.groupTypes,
         },
         ["groupType11"] = {
            type = "text",
        	   name = L["Group 11:"],
        	   desc = L["Sets contents of the eleventh grid group."],
        	   order = 13,
        	   disabled = InCombatLockdown,
        	   hidden = true,
        	   get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[11] end,
        	   set = function (v)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[11] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
        	   validate = GridConfigurableLayouts.groupTypes,
         },
         ["addGroup"] = {
            type = "execute",
            name = L["Add a Group"],
            desc = L["Add a group."],
            order = 14,
            disabled = function () return InCombatLockdown() or (GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups > 10) end,
            func = function ()
               num = GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups + 1
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[num] = "none"
               GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType"..num].hidden = false
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList"..num].hidden = false
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget"..num].hidden = false
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups = num
               GridConfigurableLayouts:checkUpdateCurrent()
               Waterfall:Refresh("Grid")
            end,
         },
         ["removeGroup"] = {
            type = "execute",
            name = L["Remove a Group"],
            desc = L["Remove a group."],
            order = 15,
            disabled = function () return InCombatLockdown() or (GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups < 2) end,
            func = function ()
               num = GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[num] = "none"
               GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType"..num].hidden = true
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList"..num].hidden = true
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget"..num].hidden = true
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups = num - 1
               GridConfigurableLayouts:checkUpdateCurrent()
               Waterfall:Refresh("Grid")
            end,
         },    
      },
   },
   ["editNameLists"] = {
      type = "group",
      name = L["Name Lists"],
      desc = L["Edit name lists to apply to groups in the current layout."],
      order = 29,
      disabled = InCombatLockdown,
      args = {
         ["nameList1"] = {
            type = "text",
  	         name = L["Group 1:"],
  	         desc = L["Sets name list for the first grid group (comma separated list)."],
            usage = "",
  	         order = 1,
  	         disabled = InCombatLockdown,
  	         get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[1] end,
  	         set = function (v)
               v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[1] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
         },
         ["addTarget1"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 1."],
            order = 2,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[1] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[1] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[1] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList2"] = {
            type = "text",
    	      name = L["Group 2:"],
    	      desc = L["Sets name list for the second grid group (comma separated list)."],
    	      usage = "",
            order = 3,
            disabled = InCombatLockdown,
    	      get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[2] end,
    	      set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[2] = v
                GridConfigurableLayouts:checkUpdateCurrent()
            end,
         },
         ["addTarget2"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 2."],
            order = 4,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[2] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[2] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[2] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList3"] = {
            type = "text",
            name = L["Group 3:"],
            desc = L["Sets name list for the third grid group (comma separated list)."],
            usage = "",
            order = 5,
            disabled = InCombatLockdown,
            get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[3] end,
            set = function (v)
               v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[3] = v
               GridConfigurableLayouts:checkUpdateCurrent()
            end,
         },
         ["addTarget3"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 3."],
            order = 6,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[3] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[3] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[3] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList4"] = {
             type = "text",
             name = L["Group 4:"],
             desc = L["Sets name list for the fourth grid group (comma separated list)."],
             usage = "",
             order = 7,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[4] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[4] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget4"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 4."],
            order = 8,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[4] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[4] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[4] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList5"] = {
             type = "text",
             name = L["Group 5:"],
             desc = L["Sets name list for the fifth grid group (comma separated list)."],
             usage = "",
             order = 9,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[5] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[5] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget5"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 5."],
            order = 10,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[5] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[5] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[5] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList6"] = {
             type = "text",
             name = L["Group 6:"],
             desc = L["Sets name list for the sixth grid group (comma separated list)."],
             usage = "",
             order = 11,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[6] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[6] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget6"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 6."],
            order = 12,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[6] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[6] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[6] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList7"] = {
             type = "text",
             name = L["Group 7:"],
             desc = L["Sets name list for the seventh grid group (comma separated list)."],
             usage = "",
             order = 13,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[7] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[7] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget7"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 7."],
            order = 14,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[7] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[7] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[7] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList8"] = {
             type = "text",
             name = L["Group 8:"],
             desc = L["Sets name list for the eighth grid group (comma separated list)."],
             usage = "",
             order = 15,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[8] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[8] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget8"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 8."],
            order = 16,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[8] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[8] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[8] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList9"] = {
             type = "text",
             name = L["Group 9:"],
             desc = L["Sets name list for the ninth grid group (comma separated list)."],
             usage = "",
             order = 17,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[9] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[9] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget9"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 9."],
            order = 18,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[9] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[9] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[9] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList10"] = {
             type = "text",
             name = L["Group 10:"],
             desc = L["Sets name list for the tenth grid group (comma separated list)."],
             usage = "",
             order = 19,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[10] end,
             set = function (v)
                v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[10] = v
                GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget10"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 10."],
            order = 20,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[10] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[10] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[10] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["nameList11"] = {
             type = "text",
             name = L["Group 11:"],
             desc = L["Sets name list for the eleventh grid group (comma separated list)."],
             usage = "",
             order = 21,
             disabled = InCombatLockdown,
             get = function () return GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[11] end,
             set = function (v)
                  v = v:gsub("(%a)(%a+)", function (a,b) return a:upper() .. b:lower() end)
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[11] = v
                  GridConfigurableLayouts:checkUpdateCurrent()
             end,
         },
         ["addTarget11"] = {
            type = "execute",
            name = L["Add Target"],
            desc = L["Add your target to the name list for group 11."],
            order = 22,
            disabled = InCombatLockdown,
            func = function ()
               local name = GetUnitName("target")
               if name and (UnitInParty("target") or UnitInRaid("target")) then
                  if GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[11] ~= "" then
                     name = ", " .. name
                  end
                  GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[11] =
                     GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[11] .. name
                  GridConfigurableLayouts:checkUpdateCurrent()
                  Waterfall:Refresh("Grid")
               end
            end,
         },
         ["spacer1"] = {
		      type = "header",
            name = L[" "],
            order = 50,
	      },
         ["spacer2"] = {
		      type = "header",
            name = L[" "],
            order = 51,
	      },
         ["addGroup"] = {
            type = "execute",
            name = L["Add a Group"],
            desc = L["Add a group."],
            order = 52,
            disabled = function () return InCombatLockdown() or (GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups > 10) end,
            func = function ()
               num = GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups + 1
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[num] = "none"
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[num] = ""
               GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType"..num].hidden = false
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList"..num].hidden = false
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget"..num].hidden = false
               GridConfigurableLayouts:checkUpdateCurrent()
               Waterfall:Refresh("Grid")
            end,
         },
         ["removeGroup"] = {
            type = "execute",
            name = L["Remove a Group"],
            desc = L["Remove a group."],
            order = 53,
            disabled = function () return InCombatLockdown() or (GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups < 2) end,
            func = function ()
               num = GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].groupType[num] = "none"
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].nameList[num] = ""
               GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType"..num].hidden = true
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList"..num].hidden = true
               GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget"..num].hidden = true
               GridConfigurableLayouts.db.profile.layouts[GridConfigurableLayouts.db.profile.configLayout].numGroups = num - 1
               GridConfigurableLayouts:checkUpdateCurrent()
               Waterfall:Refresh("Grid")
            end,
         },
      },
   },
   ["globalOptions"] = {
      type = "group",
      name = L["Global Options"],
      desc = L["Set options that apply to all layouts created with this module."],
      order = 31,
      disabled = InCombatLockdown,
      args = {
         ["createBordersHeader"] = { 
      	   type = "header",
      	   name = L["Custom Border Colors"],
      	   order = 60,
      	},
         ["borderFilterSelection"] = {
            type = "text",
            name = L["Filter to apply border too:"],
            desc = L["Choose filter for which to set color."],
            order = 62,
            disabled = InCombatLockdown,
            get = function () return GridConfigurableLayouts.db.profile.filterToColor end,
            set = function (v)
               GridConfigurableLayouts.db.profile.filterToColor = v
               GridLayout.options.args["GridConfigurableLayouts"].args["globalOptions"].args["borderColor"].name = "Border Color for "  .. GridConfigurableLayouts.groupTypes[GridConfigurableLayouts.db.profile.filterToColor]
               Waterfall:Refresh("Grid")
            end,
            validate = GridConfigurableLayouts.groupTypes,
         },
         ["borderColor"] = {
      		type = "color",
      		name = L["Border Color"],
      		desc = L["Adjust border color and alpha."],
      		order = 63,
      		disabled = InCombatLockdown,
      		get = function ()
        			local filter = GridConfigurableLayouts.db.profile.filterToColor
               local settings = GridConfigurableLayouts.db.profile
               return settings.filterColors[filter]["r"], settings.filterColors[filter]["g"], settings.filterColors[filter]["b"], settings.filterColors[filter]["a"]
      		end,
      		set = function (r, g, b, a)
      			local filter = GridConfigurableLayouts.db.profile.filterToColor
               local settings = GridConfigurableLayouts.db.profile
      			settings.filterColors[filter]["r"], settings.filterColors[filter]["g"],settings.filterColors[filter]["b"],settings.filterColors[filter]["a"] = r, g, b, a
               GCLHooks:UpdateSize()
            end,
            hasAlpha = true
      	},
         ["spacer7"] = {
      		type = "header",
      		name = L[" "],
      		order = 65,
      	},
      	["spacer8"] = {
      		type = "header",
      		name = L[" "],
      		order = 66,
      	},
      	["spacer9"] = {
      		type = "header",
      		name = L[" "],
      		order = 67,
      	},
      	["otherSettingsHeader"] = { 
      	   type = "header",
      	   name = L["Everything Else"],
      	   order = 68,
      	},
         ["checkOOZFrequency"] = {
      	   type = "range",
       		name = L["Zone change check frequency"],
        	   desc = L["Frequency with which to check for raidmember zone changes."],
            order = 69,
            disabled = InCombatLockdown,
            max = 20,
            min = 1,
            step = 1,
            get = function ()	return GridConfigurableLayouts.db.profile.checkOOZFrequency end,
      	   set = function (v)
         		GridConfigurableLayouts.db.profile.checkOOZFrequency = v
         	   GridConfigurableLayouts:checkUpdateCurrent()
      	   end,
         },
         ["spacer10"] = {
      		type = "header",
      		name = L[" "],
      		order = 70,
      	},
      	["spacer11"] = {
      		type = "header",
      		name = L[" "],
      		order = 71,
      	},
         ["resetToDefaults"] = {
            type = "execute",
            name = L["Reset all Options"],
            desc = L["Reset all settings and layouts. This will delete any new layouts you have created."],
            order = 72,
            disabled = InCombatLockdown,
            func = function () GridConfigurableLayouts:resetAllOptions() end,
         },
         ["spacer12"] = {
      		type = "header",
      		name = L[" "],
      		order = 73,
      	},
         ["resetWarning"] = {
      		type = "header",
      		name = L["Warning: you should reload the UI or log out and"],
      		order = 74,
      	},
      	["resetWarning2"] = {
      		type = "header",
      		name = L["in after reset!!"],
      		order = 75,
      	},
      	["spacer13"] = {
      		type = "header",
      		name = L[" "],
      		order = 76,
      	},
      },
   },
}
---}}}


--{{{ Place options into the Grid options under Layout
GridLayout.options.args["advanced"]["order"] = 98
GridLayout.options.args["GridConfigurableLayouts"] = {
	type = "group",
	name = L["Configure Layouts"],
	desc = L["Options for creating custom layouts."],
   order = 99,
	disabled = InCombatLockdown,
	args = GCLOptions
}
--}}}


---{{{ Initialization, reset, etc., . . .
function GridConfigurableLayouts:OnInitialize()
   self.super.OnInitialize(self)
end


function GridConfigurableLayouts:OnEnable()
   self:loadNewConfig(self.db.profile.configLayout)
   self:addLayouts()
   GridLayout.options.args["GridConfigurableLayouts"].args["configLayout"].validate = GridConfigurableLayouts.db.profile.layoutNames
   GCLHooks:Hook(GridLayout, "ReloadLayout")
   GCLHooks:ReloadLayout()
end


function GridConfigurableLayouts:Reset()
   self.super.Reset(self)
   GCLHooks:ReloadLayout()
end
---}}}


---{{{ Registrations and Callback functions
function GridConfigurableLayouts:doRegister()
   self:RegisterEvent("Grid_EnteringCombat", GridConfigurableLayouts.setCombatLockdown)
   self:RegisterEvent("Grid_LeavingCombat", GridConfigurableLayouts.removeCombatLockdown)
   self:RegisterEvent("Grid_RosterUpdated", GCLHooks.ReloadLayout)
   talentLib.RegisterCallback(GridConfigurableLayouts, 'LibGroupTalents_RoleChange')
   if not combatLockdown and self:checkUsingOOZ() then
      self:ScheduleRepeatingEvent("GridConfigurableLayouts_OOZ_Check", GridConfigurableLayouts.OOZCheck, GridConfigurableLayouts.db.profile.checkOOZFrequency )
   end   
   isRegistered = true
end


function GridConfigurableLayouts:doUnregister()
   self:UnregisterEvent("Grid_EnteringCombat")
   self:UnregisterEvent("Grid_LeavingCombat")
   self:UnregisterEvent("Grid_RosterUpdated")
   talentLib.UnregisterCallback(GridConfigurableLayouts, "LibGroupTalents_RoleChange")
   self:CancelScheduledEvent("GridConfigurableLayouts_OOZ_Check")
   isRegistered = false
end


function GridConfigurableLayouts:setCombatLockdown()
   combatLockdown = true
   GridConfigurableLayouts:CancelScheduledEvent("GridConfigurableLayouts_OOZ_Check")
end


function GridConfigurableLayouts:removeCombatLockdown()
   combatLockdown = false
   if GridConfigurableLayouts:isActive() and GridConfigurableLayouts:checkUsingOOZ() then
      GridConfigurableLayouts:ScheduleRepeatingEvent("GridConfigurableLayouts_OOZ_Check", GridConfigurableLayouts.OOZCheck, GridConfigurableLayouts.db.profile.checkOOZFrequency)
   end
   if reloadLayoutQueued then
      GCLHooks:ReloadLayout()
   end
end    
    

function GCLHooks:ReloadLayout(self, layoutName)
   if combatLockdown then
      reloadLayoutQueued = true
   else
      if GridConfigurableLayouts:isActive() then
         GridConfigurableLayouts:redoGroups()
      end                                           
	   GridLayout:LoadLayout(GridLayout.db.profile.layouts[GridRoster:GetPartyState()])
	end
end


function GCLHooks:UpdateSize()
   -- This hook is used to place group borders whenever GridLayout refreshes it's own outer border
   if GridConfigurableLayouts:isActive() and GridConfigurableLayouts.db.profile.layouts[GridLayout.db.profile.layouts[GridRoster:GetPartyState()]].createBorders then
      GridConfigurableLayouts:makeBorders()
	end
end   


function GCLHooks:PlaceGroup(context, layoutGroup, groupNumber)
   -- This hook is used when we need to adjust group placement to make room for group borders
   if GridConfigurableLayouts:isActive() and GridConfigurableLayouts.db.profile.layouts[GridLayout.db.profile.layouts[GridRoster:GetPartyState()]].createBorders then
      GridConfigurableLayouts:adjustGroup(layoutGroup, groupNumber)
	end
end   


function GridConfigurableLayouts:OOZCheck()
   -- Periodically checks if any raid member has changed zones
   if not combatLockdown then
      if GridConfigurableLayouts:isActive() then
         for guid, unit in GridRoster:IterateRoster() do
            if (string.sub(unit, 1, 7) ~= "raidpet") then
               local zone = GetRealZoneText()
               if (string.sub(unit, 1, 4) == "raid") then
                  local raidIndex = string.sub(unit, 5)
                  local _, _, _, _, _, _, temp_zone = GetRaidRosterInfo(raidIndex)
                  zone = temp_zone or zone
      	      end
               if rosterZoneList[guid] ~= zone and (zone ~= "Offline" or currentLayout.offlineIsOOZ) then
                  GCLHooks:ReloadLayout()
                  return
               end
            end
         end
      end
   end
end   


function GridConfigurableLayouts:LibGroupTalents_RoleChange(event, guid, unit)
   GCLHooks:ReloadLayout()
end
---}}}


---{{{ Core functions
function GridConfigurableLayouts:createLayout(name)
   -- Occurs when "Create New Layout" button is pressed, creates a copy of GCL_Default with a new name
   if name and name ~= "" and GridLayout.layoutSettings[name] == nil then
      GridLayout:AddLayout(name, emptyLayout)
      self.db.profile.layouts[name] = {
         allowRepeats = false,
         numGroups = 6,
         groupType = {"tank", "melee", "healer", "ranged", "pets", "ooz", "none", "none", "none", "none", "none" },
         nameList = {"", "", "", "", "", "", "", "", "", "", "" },
         petOptions = {
            ["allPets"] = false,
            ["HUNTER"] = true,
            ["WARLOCK"] = true,
            ["DEATHKNIGHT"] = true,
         },
      }
      table.insert(self.db.profile.layoutNames, name)
      self:loadNewConfig(name)
      self.newLayoutName = ""      
      self:checkUpdateCurrent()
   end
end


function GridConfigurableLayouts:removeLayout(name)
   -- Occurs when "Remove Layout" button is pressed
   if self.db.profile.layouts[name] and name ~= "GCL Default" then
      GridLayout.layoutSettings[name] = nil
    	for _, party_type in ipairs(GridRoster.party_states) do
    		for i, layoutName in ipairs(GridLayout.options.args[party_type .. "layout"].validate) do
    		   if name == layoutName then
               table.remove(GridLayout.options.args[party_type .. "layout"].validate, i)
            end
    		end
    	end
      self.db.profile.layouts[name] = nil
      for i, layoutName in ipairs(self.db.profile.layoutNames) do
         if name == layoutName then
            table.remove(self.db.profile.layoutNames, i)
         end
      end
      if self.db.profile.configLayout == name then
         self:loadNewConfig("GCL Default")
      end
      self.newLayoutName = ""
      self:checkUpdateCurrent()
   end
end   
   

function GridConfigurableLayouts:setCreateBorders(doCreate)
   -- Called when creation of group borders is enabled or disabled
   if doCreate then
      if not GCLHooks:IsHooked(GridLayout, "UpdateSize") then
         GCLHooks:SecureHook(GridLayout, "UpdateSize")
      end
      if not GCLHooks:IsHooked(GridLayout, "PlaceGroup") then
         GCLHooks:SecureHook(GridLayout, "PlaceGroup")
      end
      GridLayout.frame:DisableDrawLayer("BORDER")
      GridLayout.frame:DisableDrawLayer("BACKGROUND")
   else
      if GCLHooks:IsHooked(GridLayout, "PlaceGroup") then
         GCLHooks:Unhook(GridLayout, "PlaceGroup")
      end
      if GCLHooks:IsHooked(GridLayout, "UpdateSize") then
         GCLHooks:Unhook(GridLayout, "UpdateSize")
      end
      for _, f in pairs(outerFrames) do
         f:Hide()
      end
      for _, f in pairs(outerPetFrames) do
         f:Hide()
      end
      GridLayout.frame:EnableDrawLayer("BORDER")
      GridLayout.frame:EnableDrawLayer("BACKGROUND")
   end
end


function GridConfigurableLayouts:resetAllOptions()
   for layoutName, _ in pairs(self.db.profile.layouts) do
      self:removeLayout(layoutName)
   end
   self:doUnregister()
   self.core:ResetDB("GridConfigurableLayouts", "profile")
   -- Next line is needed because db objects are newly re-made, so .validate points to the wrong place now
   GridLayout.options.args["GridConfigurableLayouts"].args["configLayout"].validate = GridConfigurableLayouts.db.profile.layoutNames
   self:loadNewConfig("GCL Default")
   self:addLayouts()
   GCLHooks:ReloadLayout()
   Waterfall:Refresh("Grid")   
end


function GridConfigurableLayouts:redoGroups()
   -- The core function of this module: processes the roster and builds the current layout
   -- which it feeds to GridLayout

   local groupList = {"", "", "", "", "", "", "", "", "", "", "" }
   local petGroupFilter = ""
   local oozList = ""
   local usingooz = self:checkUsingOOZ()
   local revisedNameList = {}
   local nameListed = {}
   
   -- make a clean copy of namelists with no bogus names
   -- (because names that are not in raid can block legit names from appearing)
   for i = 1, currentLayout.numGroups do
      nl = currentLayout.nameList[i] .. ","
      tempnl = ""
      for name in gmatch(nl, "%s*(%w+)%s*,")   do
         if not nameListed[name] and GridRoster:GetGUIDByFullName(name) then
            nameListed[name] = true
            tempnl = tempnl .. "," .. name
         end
      end
      revisedNameList[i] = tempnl
   end
   -- iterate thru the roster and place units in groups
   for guid, unit in GridRoster:IterateRoster() do
      if (string.sub(unit, 1, 7) ~= "raidpet") and
            (string.sub(unit, 1, 8) ~= "partypet") and
            (unit ~= "pet") then
         local name, raidgroup, isMT, zone = self:getUnitInfo(unit, guid)
         local role = self:getRole(guid, unit)
         -- first check if this unit belongs in an ooz group
         if usingooz then 
            if zone ~= "Offline" then
               rosterZoneList[guid] = zone
            elseif not currentLayout.offlineIsOOZ then
               zone =  rosterZoneList[guid]
            end
            if zone ~= GetRealZoneText() and (currentLayout.allowRepeats or not nameListed[name]) then
               oozList = oozList .. "," .. name
               nameListed[name] = true
            end
         end
         -- then fill the groups in order
         for i = 1, currentLayout.numGroups, 1 do
            if currentLayout.allowRepeats or not nameListed[name] then
               if (role == currentLayout.groupType[i]) or
                     (currentLayout.groupType[i] == "blizztank" and isMT) or
                     (currentLayout.groupType[i] == raidgroup) or
                     (currentLayout.groupType[i] == "guild" and UnitIsInMyGuild(unit))
                     then
                  groupList[i] = groupList[i] .. "," .. name
                  nameListed[name] = true
               end
            end
         end
      end
   end
   -- if there is an ooz group, fill it
   if usingooz then
      for i = 1, currentLayout.numGroups, 1 do
         if currentLayout.groupType[i] == "ooz" then
            groupList[i] = groupList[i] .. "," .. oozList
         end
      end
   end
   -- add namelists to the groups we have built
   for i = 1, currentLayout.numGroups do
      if revisedNameList[i] ~= "" then
         groupList[i] = groupList[i] .. "," .. revisedNameList[i]
      end
   end
   -- create groupFilter for pet group
   if not currentLayout.petOptions["allPets"] then
      for class, enabled in pairs(currentLayout.petOptions) do
         if class ~= "allPets" and enabled == true then
            petGroupFilter = petGroupFilter .. "," .. class
         end
      end
   end
   -- pass the updated layout to GridLayout
   local layoutName = GridLayout.db.profile.layouts[GridRoster:GetPartyState()]
   local realIndex = 1
   for i = 1, 11, 1 do
      GridLayout.layoutSettings[layoutName][i] = nil
      if currentLayout.groupType[i] ~= "none" then
         GridLayout.layoutSettings[layoutName][realIndex] = {}
         if currentLayout.groupType[i] == "pets" then
            GridLayout.layoutSettings[layoutName][realIndex]["isPetGroup"] = true
            GridLayout.layoutSettings[layoutName][realIndex]["groupFilter"] = "1,2,3,4,5,6,7,8"
            GridLayout.layoutSettings[layoutName][realIndex]["nameList"] = ""
            if not currentLayout.petOptions["allPets"] then
               GridLayout.layoutSettings[layoutName][realIndex]["groupFilter"] = petGroupFilter
            end
         else
            GridLayout.layoutSettings[layoutName][realIndex]["isPetGroup"] = false
            GridLayout.layoutSettings[layoutName][realIndex]["groupFilter"] = nil
            GridLayout.layoutSettings[layoutName][realIndex]["nameList"] = groupList[i]
         end
      realIndex = realIndex + 1
      end
   end
end


function GridConfigurableLayouts:makeBorders()
   -- Implements group borders around existing groups
   local groupCount = 1
   local groupColors, petGroupColors, totalGroups = self:getGroupColors()
   local borderTexture = media:Fetch(media.MediaType.BORDER, GridLayout.db.profile.borderTexture)
   
   for _, f in pairs(outerFrames) do
      f:Hide()
   end
   
   for _, f in pairs(outerPetFrames) do
      f:Hide()
   end
   
   for i, layoutGroup in ipairs(GridLayout.layoutGroups) do
		if layoutGroup:IsFrameVisible() and hasVisibleUnitFrame(layoutGroup.frame) then
         local f = outerFrames[i] or CreateFrame("Frame", "GCLOuterFrame" .. i, GridLayout.frame)
         local x, y = layoutGroup.frame:GetLeft() - GridLayout.frame:GetLeft(), layoutGroup.frame:GetTop() - GridLayout.frame:GetTop()
         local width, height = layoutGroup:GetFrameWidth(), layoutGroup:GetFrameHeight()
         x = x - 5
         y = y + 5
         width = width + 10
         height = height + 10
         f:SetWidth( width)
         f:SetHeight( height)
         f:SetPoint("TOPLEFT", x, y)
         f:SetBackdrop({
				bgFile = "Interface\\ChatFrame\\ChatFrameBackground", tile = true, tileSize = 16,
				edgeFile = borderTexture, edgeSize = 16,
				insets = {left = 4, right = 4, top = 4, bottom = 4},
			})
         local color = groupColors[i]
         f:SetBackdropBorderColor(color.r, color.g, color.b, color.a)
			f:SetBackdropColor(0, 0, 0, 0)
			f:Show()
			outerFrames[i] = f
		end
	end
   for i, layoutGroup in ipairs(GridLayout.layoutPetGroups) do
		if layoutGroup:IsFrameVisible() and hasVisibleUnitFrame(layoutGroup.frame) then
         local f = outerPetFrames[i] or CreateFrame("Frame", "GCLOuterPetFrame" .. i, GridLayout.frame)
         local x, y = layoutGroup.frame:GetLeft() - GridLayout.frame:GetLeft(), layoutGroup.frame:GetTop() - GridLayout.frame:GetTop()
         local width, height = layoutGroup:GetFrameWidth(), layoutGroup:GetFrameHeight()
         x = x - 5
         y = y + 5
         width = width + 10
         height = height + 10
         f:SetWidth( width)
         f:SetHeight( height)
         f:SetPoint("TOPLEFT", x, y)
         f:SetBackdrop({
				bgFile = "Interface\\ChatFrame\\ChatFrameBackground", tile = true, tileSize = 16,
				edgeFile = borderTexture, edgeSize = 16,
				insets = {left = 4, right = 4, top = 4, bottom = 4},
			})
         local color = petGroupColors[i]
         f:SetBackdropBorderColor(color.r, color.g, color.b, color.a)
			f:SetBackdropColor(0, 0, 0, 0)
			f:Show()
			outerPetFrames[i] = f
		end
	end
end


function GridConfigurableLayouts:adjustGroup(layoutGroup, groupNumber)
   -- For when group borders are active: Adjusts the placement of the group frames
   -- created by GridLayout to make room for our group borders
   local f = layoutGroup.frame
   local GLSettings = GridLayout.db.profile
   local horizontal = GLSettings.horizontal
   local groupAnchor = GLSettings.groupAnchor
   
   local adjustX, adjustY = 0, 0
   
   if horizontal then
      adjustX = 0
      if groupAnchor == "TOPLEFT" or groupAnchor == "TOPRIGHT" then
         adjustY = -10
      else
         adjustY = 10 
      end
   else
      adjustY = 0
      if groupAnchor == "TOPLEFT" or groupAnchor == "BOTTOMLEFT" then
         adjustX = 10
      else
         adjustX = -10
      end
   end
          
   local p, rT, rP, x, y = f:GetPoint(1)
   f:SetPoint(p, rT, rP, x + adjustX, y + adjustY) 
end
---}}}


---{{{ other functions
function GridConfigurableLayouts:isActive()
   -- Checks if the active layout is one of ours, and if so, makes sure we are registered
   -- to react to everything we need to track
   local party_type = GridRoster:GetPartyState()
   currentLayout = self.db.profile.layouts[GridLayout.db.profile.layouts[party_type]]
   self:setCreateBorders(currentLayout and currentLayout.createBorders)
   if currentLayout and not isRegistered then
      self:doRegister()
   elseif not currentLayout and isRegistered then
      self:doUnregister()
   end
   return (not (not currentLayout))
end


function GridConfigurableLayouts:checkUpdateCurrent()
   -- When a layout is modified in the options, check if it is the currently active layout
   -- and, if so, reload it with the modified settings
   local party_type = GridRoster:GetPartyState()
   if GridLayout.db.profile.layouts[party_type] == self.db.profile.configLayout then
      self:CancelScheduledEvent("GridConfigurableLayouts_OOZ_Check")
      if not combatLockdown and self:checkUsingOOZ() then
         self:ScheduleRepeatingEvent("GridConfigurableLayouts_OOZ_Check", GridConfigurableLayouts.OOZCheck, GridConfigurableLayouts.db.profile.checkOOZFrequency)                                                                                                                                                                       
      end
      GCLHooks:ReloadLayout()
   end
end            


function GridConfigurableLayouts:getUnitInfo(unit, guid)
   -- The function name says it all
   if (string.sub(unit, 1, 4) == "raid") then
      local raidIndex = string.sub(unit, 5)
      local name, raidgroup, isMT, temp_zone
      local zone = GetRealZoneText()
      name = GridRoster:GetFullNameByGUID(guid)
      _, _, raidgroup, _, _, _, temp_zone, _, _, blizzRole = GetRaidRosterInfo(raidIndex)
      zone = temp_zone or zone -- this deals with a Blizz bug where reloading ui causes GetRaidRosterInfo to return empty zone info for player
      isMT = (blizzRole == "MAINTANK")
      raidgroup = "rg" .. raidgroup
      return name, raidgroup, isMT, zone 
   end
   -- we are solo or in a party
   local name = GridRoster:GetFullNameByGUID(guid)   
   return name, "rg1", false, GetRealZoneText() -- we can't get zone info for party members!?!?
end


function GridConfigurableLayouts:checkUsingOOZ()
   -- Checks if there is an "Out of zone" group in the current layout
   for _, groupType in ipairs(currentLayout.groupType) do
      if groupType == "ooz" then
         return true
      end
   end
   return false
end


function GridConfigurableLayouts:getRole(guid, unit)
   -- Use GroupTalentLib to determine the raid role of a unit
   local _, class = UnitClass(unit)
   local role = (class == "HUNTER" and "ranged") or talentLib:GetGUIDRole(guid)
	if role == "caster" then
      role = "ranged"
	end
	-- if no role was returned use a default until the unit can be inspected
   if role ~= "tank" and role ~= "melee" and role ~= "healer" and role ~= "ranged" then
      if class == "ROGUE" or class == "WARRIOR" or class == "DEATHKNIGHT" then
         role = "melee"
      elseif class == "WARLOCK" or class == "MAGE" or class == "HUNTER" then
         role = "ranged"
      elseif class == "PALADIN" or class == "DRUID" or class == "PRIEST" or class == "SHAMAN" then
         role = "healer"
      end
	end
   return role
end


function GridConfigurableLayouts:getGroupColors()
   -- Used by MakeBorders, this creates tables of group colors that match
   -- the group borders and pet group borders in order of their creation 
   local settings = self.db.profile
   local i, j, k = 0, 0, 0
   local groupColors = {}
   local petGroupColors = {}
   for _, groupType in pairs(currentLayout.groupType) do
      if groupType == "pets" then
         j = j + 1
         k = k + 1
         gc = settings.filterColors["pets"] 
         petGroupColors[j] =  {r = gc.r, g = gc.g, b = gc.b, a = gc.a}
         petGroupColors[j]["realIndex"] = k
      elseif groupType == "none" then
         break
      else
         i = i + 1
         k = k + 1
         gc = settings.filterColors[groupType] 
         groupColors[i] =  {r = gc.r, g = gc.g, b = gc.b, a = gc.a}
         groupColors[i]["realIndex"] = k
      end
   end
   return groupColors, petGroupColors, i + j
end


function GridConfigurableLayouts:addLayouts()
   -- Adds placeholders for all our layouts, so that they are visible to GridLayout
   for _, name in ipairs(self.db.profile.layoutNames) do
      if GridLayout.layoutSettings[name] == nil then
         GridLayout:AddLayout(name, emptyLayout)
      end
   end
end


function GridConfigurableLayouts:loadNewConfig(layoutName)
   -- When we choose a new layout to configure, we have a few things to do
   self.db.profile.configLayout = layoutName
   GridLayout.options.args["GridConfigurableLayouts"].args["globalOptions"].args["borderColor"].name = "Border Color for "  .. self.groupTypes[self.db.profile.filterToColor]
   if not self.db.profile.layouts[layoutName].numGroups then
      for i = 11, 1, -1 do
         if self.db.profile.layouts[layoutName].groupType[i] ~= "none" then
            self.db.profile.layouts[layoutName].numGroups = i
            break
         end
      end
   end
   for i = 11, self.db.profile.layouts[layoutName].numGroups + 1, -1 do
      GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType" .. i].hidden = true
      GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList" .. i].hidden = true
      GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget".. i].hidden = true       
   end
   for i = 1, self.db.profile.layouts[layoutName].numGroups, 1 do
      GridLayout.options.args["GridConfigurableLayouts"].args["editGroupFilters"].args["groupType" .. i].hidden = false
      GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["nameList" .. i].hidden = false
      GridLayout.options.args["GridConfigurableLayouts"].args["editNameLists"].args["addTarget".. i].hidden = false
   end
end
---}}}